{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"id": "89cf2628",
"metadata": {},
"source": [
"# Transformer Example\n",
"\n",
"In this notebook we will present examples of transformers in `power-grid-model`. \n",
"\n",
"Both two-winding transformer and three-winding transformer are covered. We will do one-time power flow calculation and one-time state estimation for both types of tranformers.\n",
"\n",
"This notebook serves as an example of how to use the Python API. For detailed API documentation, refer to\n",
"[Python API reference](../api_reference/python-api-reference.md)\n",
"and [Native Data Interface](../advanced_documentation/native-data-interface.md).\n",
"\n",
"## Transformer (Two-winding Transformer)\n",
"\n",
"Transformer is described as a pi model in `power-grid-model`, and it belongs to the `branch` component type which connects two nodes with possibly different voltage levels.\n",
"\n",
"### Example Network\n",
"\n",
"We use a simple network with 2 nodes, 1 source, 1 load and 1 transformer. As shown below:\n",
"\n",
"```txt\n",
" source_1 --- node_2 --- transformer_3 --- node_4 --- load_5\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "ae11dc9a",
"metadata": {},
"outputs": [],
"source": [
"# some basic imports\n",
"import numpy as np\n",
"import pandas as pd\n",
"\n",
"from power_grid_model import (\n",
" AttributeType,\n",
" BranchSide,\n",
" CalculationMethod,\n",
" CalculationType,\n",
" ComponentType,\n",
" DatasetType,\n",
" LoadGenType,\n",
" MeasuredTerminalType,\n",
" PowerGridModel,\n",
" TapChangingStrategy,\n",
" initialize_array,\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "f983cef7",
"metadata": {},
"source": [
"### Input Dataset\n",
"\n",
"We create an input dataset by using the helper function `initialize_array`. \n",
"\n",
"Please refer to [Components](../user_manual/components.md) for detailed explanation of all component types and their input/output attributes."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "6f008736",
"metadata": {},
"outputs": [],
"source": [
"# node\n",
"node = initialize_array(DatasetType.input, ComponentType.node, 2)\n",
"node[AttributeType.id] = np.array([2, 4])\n",
"node[AttributeType.u_rated] = [1e4, 4e2]\n",
"\n",
"# load\n",
"sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 1)\n",
"sym_load[AttributeType.id] = [5]\n",
"sym_load[AttributeType.node] = [4]\n",
"sym_load[AttributeType.status] = [1]\n",
"sym_load[AttributeType.type] = [LoadGenType.const_power]\n",
"sym_load[AttributeType.p_specified] = [1e3]\n",
"sym_load[AttributeType.q_specified] = [5e3]\n",
"\n",
"# source\n",
"source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
"source[AttributeType.id] = [1]\n",
"source[AttributeType.node] = [2]\n",
"source[AttributeType.status] = [1]\n",
"source[AttributeType.u_ref] = [1.0]\n",
"\n",
"# transformer\n",
"transformer = initialize_array(DatasetType.input, ComponentType.transformer, 1)\n",
"transformer[AttributeType.id] = [3]\n",
"transformer[AttributeType.from_node] = [2]\n",
"transformer[AttributeType.to_node] = [4]\n",
"transformer[AttributeType.from_status] = [1]\n",
"transformer[AttributeType.to_status] = [1]\n",
"transformer[AttributeType.u1] = [1e4]\n",
"transformer[AttributeType.u2] = [4e2]\n",
"transformer[AttributeType.sn] = [1e5]\n",
"transformer[AttributeType.uk] = [0.1]\n",
"transformer[AttributeType.pk] = [1e3]\n",
"transformer[AttributeType.i0] = [1.0e-6]\n",
"transformer[AttributeType.p0] = [0.1]\n",
"transformer[AttributeType.winding_from] = [2]\n",
"transformer[AttributeType.winding_to] = [1]\n",
"transformer[AttributeType.clock] = [5]\n",
"transformer[AttributeType.tap_side] = [0]\n",
"transformer[AttributeType.tap_pos] = [3]\n",
"transformer[AttributeType.tap_min] = [-11]\n",
"transformer[AttributeType.tap_max] = [9]\n",
"transformer[AttributeType.tap_size] = [100]\n",
"\n",
"# all\n",
"input_data = {\n",
" ComponentType.node: node,\n",
" ComponentType.transformer: transformer,\n",
" ComponentType.sym_load: sym_load,\n",
" ComponentType.source: source,\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "d16f9dea",
"metadata": {},
"source": [
"**We can print the input dataset by converting the numpy array to dataframe.**"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "37749c7c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" id from_node to_node from_status to_status u1 u2 sn \\\n",
"0 3 2 4 1 1 10000.0 400.0 100000.0 \n",
"\n",
" uk pk ... tap_nom tap_size uk_min uk_max pk_min pk_max \\\n",
"0 0.1 1000.0 ... -128 100.0 NaN NaN NaN NaN \n",
"\n",
" r_grounding_from x_grounding_from r_grounding_to x_grounding_to \n",
"0 NaN NaN NaN NaN \n",
"\n",
"[1 rows x 31 columns]\n"
]
}
],
"source": [
"print(pd.DataFrame(input_data[ComponentType.transformer]))"
]
},
{
"cell_type": "markdown",
"id": "47a9c257",
"metadata": {},
"source": [
"### One-time Power Flow Calculation\n",
"\n",
"You can call the method `calculate_power_flow` to do a one-time calculation based on the current network data in the model.\n",
"\n",
"For detailed explanation of the arguments, batch calculations and asymmetric calculations, we refer to the [Power Flow Example](./Power%20Flow%20Example.ipynb) and [Asymmetric Calculation Example](./Asymmetric%20Calculation%20Example.ipynb). "
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "7bb0f998",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------node result------\n",
" id energized u_pu u u_angle p \\\n",
"0 2 1 0.999999 9999.994897 -4.976260e-08 1002.882212 \n",
"1 4 1 0.965618 386.247005 -2.618522e+00 -1000.000000 \n",
"\n",
" q \n",
"0 5027.744841 \n",
"1 -5000.000000 \n"
]
}
],
"source": [
"# validation (optional)\n",
"from power_grid_model.validation import assert_valid_input_data\n",
"\n",
"assert_valid_input_data(input_data=input_data, calculation_type=CalculationType.power_flow)\n",
"\n",
"# construction\n",
"model = PowerGridModel(input_data)\n",
"\n",
"# one-time power flow calculation\n",
"output_data = model.calculate_power_flow(\n",
" symmetric=True, error_tolerance=1e-8, max_iterations=20, calculation_method=CalculationMethod.newton_raphson\n",
")\n",
"\n",
"# result dataset\n",
"print(\"------node result------\")\n",
"print(pd.DataFrame(output_data[ComponentType.node]))"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "682c1c48",
"metadata": {},
"source": [
"### One-time State Estimation\n",
"Below we present a simple example of state estimation for a network with a two-winding transformer. \n",
"\n",
"NOTE: In `power-grid-model`, two-winding transformers belong to `branch` component type, therefore the `measured_terminal_type` of power sensors should be assigned to `MeasuredTerminalType.branch_from/_to`.\n",
"\n",
"For detailed explanation of the arguments, batch calculations and asymmetric calculations, we refer to the [State Estimation Example](./State%20Estimation%20Example.ipynb) and [Asymmetric Calculation Example](./Asymmetric%20Calculation%20Example.ipynb)."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "f0c8c3e8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------node result------\n",
" id energized u_pu u u_angle p \\\n",
"0 2 1 9.987392 99873.919714 0.000000 470658.914282 \n",
"1 4 1 9.209290 3683.716125 -2.617974 -446912.927660 \n",
"\n",
" q \n",
"0 4.700696e+06 \n",
"1 -4.464515e+06 \n"
]
}
],
"source": [
"# voltage sensor\n",
"sym_voltage_sensor = initialize_array(DatasetType.input, ComponentType.sym_voltage_sensor, 2)\n",
"sym_voltage_sensor[AttributeType.id] = [6, 7]\n",
"sym_voltage_sensor[AttributeType.measured_object] = [2, 4]\n",
"sym_voltage_sensor[AttributeType.u_sigma] = [1.0, 1.0]\n",
"sym_voltage_sensor[AttributeType.u_measured] = [1e5, 4e2]\n",
"\n",
"# power sensor\n",
"sym_power_sensor = initialize_array(DatasetType.input, ComponentType.sym_power_sensor, 2)\n",
"sym_power_sensor[AttributeType.id] = [8, 9]\n",
"sym_power_sensor[AttributeType.measured_object] = [3, 3]\n",
"sym_power_sensor[AttributeType.measured_terminal_type] = [\n",
" MeasuredTerminalType.branch_from,\n",
" MeasuredTerminalType.branch_to,\n",
"]\n",
"sym_power_sensor[AttributeType.power_sigma] = [1.0, 1.0]\n",
"sym_power_sensor[AttributeType.p_measured] = [2e6, 1e5]\n",
"sym_power_sensor[AttributeType.q_measured] = [2e7, 1e6]\n",
"\n",
"# use components from former input dataset cell.\n",
"input_data2 = {\n",
" ComponentType.node: node,\n",
" ComponentType.transformer: transformer,\n",
" ComponentType.sym_load: sym_load,\n",
" ComponentType.source: source,\n",
" ComponentType.sym_voltage_sensor: sym_voltage_sensor,\n",
" ComponentType.sym_power_sensor: sym_power_sensor,\n",
"}\n",
"\n",
"# validation (optional)\n",
"from power_grid_model.validation import assert_valid_input_data\n",
"\n",
"assert_valid_input_data(input_data=input_data2, calculation_type=CalculationType.state_estimation)\n",
"\n",
"# construction\n",
"model2 = PowerGridModel(input_data2)\n",
"\n",
"# one-time state estimation\n",
"output_data2 = model2.calculate_state_estimation(\n",
" symmetric=True, error_tolerance=1e-8, max_iterations=20, calculation_method=CalculationMethod.iterative_linear\n",
")\n",
"\n",
"# result dataset\n",
"print(\"------node result------\")\n",
"print(pd.DataFrame(output_data2[ComponentType.node]))"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "e3605c3e",
"metadata": {},
"source": [
"## Three-Winding Transformer\n",
"\n",
"Three-winding transformer is described as 3 transformers of pi model each connected together in star configuration, and it belongs to the `branch3` component type which connects three nodes with possibly different voltage levels.\n",
"\n",
"### Example Network\n",
"\n",
"We use a simple network with 3 nodes, 1 source, 1 load and 1 three-winding transformer. As shown below:\n",
"\n",
"```txt\n",
" source_1 --- node_2 --- three_winding_transformer_3 --- node_4 --- load_5\n",
" |\n",
" -------------------node_6 --- load_7\n",
" \n",
"```"
]
},
{
"cell_type": "markdown",
"id": "84a7f686",
"metadata": {},
"source": [
"### Input Dataset\n",
"\n",
"We use the helper function `initialize_array` to create an input dataset.\n",
"\n",
"Please refer to [Components](../user_manual/components.md) for detailed explanation of all component types and their input/output attributes."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "44c2de63",
"metadata": {},
"outputs": [],
"source": [
"# node\n",
"node = initialize_array(DatasetType.input, ComponentType.node, 3)\n",
"node[AttributeType.id] = np.array([2, 4, 6])\n",
"node[AttributeType.u_rated] = [1e4, 1e2, 1e2]\n",
"\n",
"# load\n",
"sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 2)\n",
"sym_load[AttributeType.id] = [5, 7]\n",
"sym_load[AttributeType.node] = [4, 6]\n",
"sym_load[AttributeType.status] = [1]\n",
"sym_load[AttributeType.type] = [LoadGenType.const_power]\n",
"sym_load[AttributeType.p_specified] = [1e3, 1e3]\n",
"sym_load[AttributeType.q_specified] = [5e3, 5e3]\n",
"\n",
"# source\n",
"source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
"source[AttributeType.id] = [1]\n",
"source[AttributeType.node] = [2]\n",
"source[AttributeType.status] = [1]\n",
"source[AttributeType.u_ref] = [1.0]\n",
"\n",
"# three-winding transformer\n",
"three_winding_transformer = initialize_array(DatasetType.input, ComponentType.three_winding_transformer, 1)\n",
"three_winding_transformer[AttributeType.id] = [3]\n",
"three_winding_transformer[AttributeType.node_1] = [2]\n",
"three_winding_transformer[AttributeType.node_2] = [4]\n",
"three_winding_transformer[AttributeType.node_3] = [6]\n",
"three_winding_transformer[AttributeType.status_1] = [1]\n",
"three_winding_transformer[AttributeType.status_2] = [1]\n",
"three_winding_transformer[AttributeType.status_3] = [1]\n",
"three_winding_transformer[AttributeType.u1] = [1e4]\n",
"three_winding_transformer[AttributeType.u2] = [1e2]\n",
"three_winding_transformer[AttributeType.u3] = [1e2]\n",
"three_winding_transformer[AttributeType.sn_1] = [1e5]\n",
"three_winding_transformer[AttributeType.sn_2] = [1e5]\n",
"three_winding_transformer[AttributeType.sn_3] = [1e5]\n",
"three_winding_transformer[AttributeType.uk_12] = [0.09]\n",
"three_winding_transformer[AttributeType.uk_13] = [0.06]\n",
"three_winding_transformer[AttributeType.uk_23] = [0.06]\n",
"three_winding_transformer[AttributeType.pk_12] = [1e3]\n",
"three_winding_transformer[AttributeType.pk_13] = [1e3]\n",
"three_winding_transformer[AttributeType.pk_23] = [1e3]\n",
"three_winding_transformer[AttributeType.i0] = [0]\n",
"three_winding_transformer[AttributeType.p0] = [0]\n",
"three_winding_transformer[AttributeType.winding_1] = [2]\n",
"three_winding_transformer[AttributeType.winding_2] = [1]\n",
"three_winding_transformer[AttributeType.winding_3] = [1]\n",
"three_winding_transformer[AttributeType.clock_12] = [5]\n",
"three_winding_transformer[AttributeType.clock_13] = [-7] # supports periodic input\n",
"three_winding_transformer[AttributeType.tap_side] = [0]\n",
"three_winding_transformer[AttributeType.tap_pos] = [0]\n",
"three_winding_transformer[AttributeType.tap_min] = [-10]\n",
"three_winding_transformer[AttributeType.tap_max] = [10]\n",
"three_winding_transformer[AttributeType.tap_nom] = [0]\n",
"three_winding_transformer[AttributeType.tap_size] = [1380]\n",
"\n",
"# all\n",
"input_data3 = {\n",
" ComponentType.node: node,\n",
" ComponentType.three_winding_transformer: three_winding_transformer,\n",
" ComponentType.sym_load: sym_load,\n",
" ComponentType.source: source,\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "c25444ec",
"metadata": {},
"source": [
"### One-time power flow calculation"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "b4e63620",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------node result------\n",
" id energized u_pu u u_angle p \\\n",
"0 2 1 0.999999 9999.989788 -9.966674e-08 2007.896574 \n",
"1 4 1 0.993097 99.309655 -2.618590e+00 -1000.000000 \n",
"2 6 1 0.994637 99.463733 -2.618281e+00 -1000.000000 \n",
"\n",
" q \n",
"0 10062.592544 \n",
"1 -5000.000000 \n",
"2 -5000.000000 \n"
]
}
],
"source": [
"# validation (optional)\n",
"from power_grid_model.validation import assert_valid_input_data\n",
"\n",
"assert_valid_input_data(input_data=input_data3, calculation_type=CalculationType.power_flow)\n",
"\n",
"# construction\n",
"model3 = PowerGridModel(input_data3)\n",
"\n",
"# one-time power flow calculation\n",
"output_data3 = model3.calculate_power_flow(\n",
" symmetric=True, error_tolerance=1e-8, max_iterations=20, calculation_method=CalculationMethod.newton_raphson\n",
")\n",
"\n",
"# result dataset\n",
"print(\"------node result------\")\n",
"print(pd.DataFrame(output_data3[ComponentType.node]))"
]
},
{
"cell_type": "markdown",
"id": "36f829f1",
"metadata": {},
"source": [
"### One-time State Estimation\n",
"\n",
"Below we present a simple example of state estimation for a network with a three-winding transformer. \n",
"\n",
"NOTE: In `power-grid-model`, three-winding transformers belong to `branch3` component type, therefore the `measured_terminal_type` of power sensors should be assigned to `MeasuredTerminalType.branch3_1/_2/_3`.\n",
"\n",
"For detailed explanation of the arguments, batch calculations and asymmetric calculations, we refer to the [State Estimation Example](./State%20Estimation%20Example.ipynb) and [Asymmetric Calculation Example](./Asymmetric%20Calculation%20Example.ipynb)."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "1ae6c043",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------three-winding transformer result------\n",
" id energized loading_1 loading_2 loading_3 loading p_1 \\\n",
"0 3 1 0.033993 0.016958 0.016967 0.033993 667.156598 \n",
"\n",
" q_1 i_1 s_1 p_2 q_2 i_2 \\\n",
"0 3333.23678 0.196261 3399.347785 -333.400686 -1662.691395 9.813068 \n",
"\n",
" s_2 p_3 q_3 i_3 s_3 \n",
"0 1695.788516 -332.889246 -1663.677083 9.813068 1696.654557 \n"
]
}
],
"source": [
"# voltage sensor\n",
"sym_voltage_sensor = initialize_array(DatasetType.input, ComponentType.sym_voltage_sensor, 3)\n",
"sym_voltage_sensor[AttributeType.id] = [8, 9, 10]\n",
"sym_voltage_sensor[AttributeType.measured_object] = [2, 4, 6]\n",
"sym_voltage_sensor[AttributeType.u_sigma] = [1.0, 1.0, 1.0]\n",
"sym_voltage_sensor[AttributeType.u_measured] = [1e4, 1e2, 1e2]\n",
"\n",
"# power sensor\n",
"sym_power_sensor = initialize_array(DatasetType.input, ComponentType.sym_power_sensor, 3)\n",
"sym_power_sensor[AttributeType.id] = [11, 12, 13]\n",
"sym_power_sensor[AttributeType.measured_object] = [3, 3, 3]\n",
"sym_power_sensor[AttributeType.measured_terminal_type] = [\n",
" MeasuredTerminalType.branch3_1,\n",
" MeasuredTerminalType.branch3_2,\n",
" MeasuredTerminalType.branch3_3,\n",
"]\n",
"sym_power_sensor[AttributeType.power_sigma] = [1.0, 1.0, 1.0]\n",
"sym_power_sensor[AttributeType.p_measured] = [2e3, 1e3, 1e3]\n",
"sym_power_sensor[AttributeType.q_measured] = [1e4, 5e3, 5e3]\n",
"\n",
"# use components from the one-time power flow calculation with three-winding transformer\n",
"input_data4 = {\n",
" ComponentType.node: node,\n",
" ComponentType.three_winding_transformer: three_winding_transformer,\n",
" ComponentType.sym_load: sym_load,\n",
" ComponentType.source: source,\n",
" ComponentType.sym_voltage_sensor: sym_voltage_sensor,\n",
" ComponentType.sym_power_sensor: sym_power_sensor,\n",
"}\n",
"\n",
"# validation (optional)\n",
"from power_grid_model.validation import assert_valid_input_data\n",
"\n",
"assert_valid_input_data(input_data=input_data4, calculation_type=CalculationType.state_estimation)\n",
"\n",
"# construction\n",
"model4 = PowerGridModel(input_data4)\n",
"\n",
"# one-time state estimation\n",
"output_data4 = model4.calculate_state_estimation(\n",
" symmetric=True, error_tolerance=1e-8, max_iterations=20, calculation_method=CalculationMethod.iterative_linear\n",
")\n",
"\n",
"# result dataset\n",
"print(\"------three-winding transformer result------\")\n",
"print(pd.DataFrame(output_data4[ComponentType.three_winding_transformer]))"
]
},
{
"cell_type": "markdown",
"id": "7fb27b941602401d91542211134fc71a",
"metadata": {},
"source": [
"## Power flow calculations with automatic tap changing\n",
"\n",
"### Example Network\n",
"\n",
"We use a simple network with 3 nodes, 1 source, 1 load, 1 line, 1 transformer and 1 transformer tap regulator. As shown below:\n",
"\n",
"```txt\n",
" (tap_side) (control side)\n",
"source_1 --- node_2 --- transformer_3 --- node_4 --- line_5 --- node_6 --- load_7\n",
" | |\n",
" transformer_tap_regulator_8 <--------/ (control voltage)\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "5ab5adba",
"metadata": {},
"source": [
"### Input Dataset\n",
"\n",
"We create an input dataset by using the helper function `initialize_array`. \n",
"\n",
"Please refer to [Components](../user_manual/components.md) for detailed explanation of all component types and their input/output attributes."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "0c89a335",
"metadata": {},
"outputs": [],
"source": [
"# node\n",
"node = initialize_array(DatasetType.input, ComponentType.node, 3)\n",
"node[AttributeType.id] = [2, 4, 6]\n",
"node[AttributeType.u_rated] = [1e4, 4e2, 4e2]\n",
"\n",
"# load\n",
"sym_load = initialize_array(DatasetType.input, ComponentType.sym_load, 1)\n",
"sym_load[AttributeType.id] = [7]\n",
"sym_load[AttributeType.node] = [6]\n",
"sym_load[AttributeType.status] = [1]\n",
"sym_load[AttributeType.type] = [LoadGenType.const_power]\n",
"sym_load[AttributeType.p_specified] = [1e3]\n",
"sym_load[AttributeType.q_specified] = [5e3]\n",
"\n",
"# source\n",
"source = initialize_array(DatasetType.input, ComponentType.source, 1)\n",
"source[AttributeType.id] = [1]\n",
"source[AttributeType.node] = [2]\n",
"source[AttributeType.status] = [1]\n",
"source[AttributeType.u_ref] = [1.0]\n",
"\n",
"# line\n",
"line = initialize_array(DatasetType.input, ComponentType.line, 1)\n",
"line[AttributeType.id] = [5]\n",
"line[AttributeType.from_node] = [4]\n",
"line[AttributeType.to_node] = [6]\n",
"line[AttributeType.from_status] = [1]\n",
"line[AttributeType.to_status] = [1]\n",
"line[AttributeType.r1] = [10.0]\n",
"line[AttributeType.x1] = [0.0]\n",
"line[AttributeType.c1] = [0.0]\n",
"line[AttributeType.tan1] = [0.0]\n",
"\n",
"# transformer\n",
"transformer = initialize_array(DatasetType.input, ComponentType.transformer, 1)\n",
"transformer[AttributeType.id] = [3]\n",
"transformer[AttributeType.from_node] = [2]\n",
"transformer[AttributeType.to_node] = [4]\n",
"transformer[AttributeType.from_status] = [1]\n",
"transformer[AttributeType.to_status] = [1]\n",
"transformer[AttributeType.u1] = [1e4]\n",
"transformer[AttributeType.u2] = [4e2]\n",
"transformer[AttributeType.sn] = [1e5]\n",
"transformer[AttributeType.uk] = [0.1]\n",
"transformer[AttributeType.pk] = [1e3]\n",
"transformer[AttributeType.i0] = [1.0e-6]\n",
"transformer[AttributeType.p0] = [0.1]\n",
"transformer[AttributeType.winding_from] = [2]\n",
"transformer[AttributeType.winding_to] = [1]\n",
"transformer[AttributeType.clock] = [5]\n",
"transformer[AttributeType.tap_side] = [0]\n",
"transformer[AttributeType.tap_pos] = [3]\n",
"transformer[AttributeType.tap_min] = [-11]\n",
"transformer[AttributeType.tap_max] = [9]\n",
"transformer[AttributeType.tap_size] = [100]\n",
"\n",
"# transformer tap regulator\n",
"transformer_tap_regulator = initialize_array(DatasetType.input, ComponentType.transformer_tap_regulator, 1)\n",
"transformer_tap_regulator[AttributeType.id] = [8]\n",
"transformer_tap_regulator[AttributeType.regulated_object] = [3]\n",
"transformer_tap_regulator[AttributeType.status] = [1]\n",
"transformer_tap_regulator[AttributeType.control_side] = [BranchSide.to_side]\n",
"transformer_tap_regulator[AttributeType.u_set] = [400.0]\n",
"transformer_tap_regulator[AttributeType.u_band] = [20.0]\n",
"transformer_tap_regulator[AttributeType.line_drop_compensation_r] = [0.0]\n",
"transformer_tap_regulator[AttributeType.line_drop_compensation_x] = [0.0]\n",
"\n",
"# all\n",
"input_data5 = {\n",
" ComponentType.node: node,\n",
" ComponentType.line: line,\n",
" ComponentType.transformer: transformer,\n",
" ComponentType.sym_load: sym_load,\n",
" ComponentType.source: source,\n",
" ComponentType.transformer_tap_regulator: transformer_tap_regulator,\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "a28369ab",
"metadata": {},
"source": [
"### One-time Power Flow Calculation\n",
"\n",
"As before, you can call the method `calculate_power_flow` to do a one-time calculation based on the current network data in the model.\n",
"\n",
"For a detailed explanation of the arguments, batch calculations and asymmetric calculations, we refer to the [Power Flow Example](./Power%20Flow%20Example.ipynb) and [Asymmetric Calculation Example](./Asymmetric%20Calculation%20Example.ipynb). "
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "2ff01266",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------node result------\n"
]
},
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" u | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 2 | \n",
" 9999.994637 | \n",
"
\n",
" \n",
" | 1 | \n",
" 4 | \n",
" 386.141058 | \n",
"
\n",
" \n",
" | 2 | \n",
" 6 | \n",
" 322.704292 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id u\n",
"0 2 9999.994637\n",
"1 4 386.141058\n",
"2 6 322.704292"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# construction\n",
"model5 = PowerGridModel(input_data5)\n",
"\n",
"# one-time power flow calculation without automatic tap changing\n",
"output_data5 = model5.calculate_power_flow()\n",
"\n",
"# Both load-side nodes node_4 and node_6 have a voltage below 400 V\n",
"print(\"------node result------\")\n",
"display(pd.DataFrame(output_data5[ComponentType.node])[[AttributeType.id, AttributeType.u]])"
]
},
{
"cell_type": "markdown",
"id": "07af8e93",
"metadata": {},
"source": [
"### Any voltage tap position strategy\n",
"\n",
"In the regular one-time power flow calculation in the example above, the voltage at the low-voltage side of the transformer is lower than 390 V.\n",
"\n",
"To get a voltage at the control side of the transformer in the acceptable voltage band as provided to the transformer tap regulator, run the power flow calculation with any the tap changing strategy set to any valid tap."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "7ad86bf0",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------node result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" u | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 2 | \n",
" 9999.994657 | \n",
"
\n",
" \n",
" | 1 | \n",
" 4 | \n",
" 393.881868 | \n",
"
\n",
" \n",
" | 2 | \n",
" 6 | \n",
" 334.529465 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id u\n",
"0 2 9999.994657\n",
"1 4 393.881868\n",
"2 6 334.529465"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"------tap regulator result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" energized | \n",
" tap_pos | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 8 | \n",
" 1 | \n",
" 1 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id energized tap_pos\n",
"0 8 1 1"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# one-time power flow calculation with automatic tap changing\n",
"output_data6 = model5.calculate_power_flow(tap_changing_strategy=TapChangingStrategy.any_valid_tap)\n",
"\n",
"# the node at the control side of the transformer now has a voltage within the specified voltage band\n",
"print(\"------node result------\")\n",
"display(pd.DataFrame(output_data6[ComponentType.node])[[AttributeType.id, AttributeType.u]])\n",
"\n",
"print(\"\\n------tap regulator result------\")\n",
"display(pd.DataFrame(output_data6[ComponentType.transformer_tap_regulator]))"
]
},
{
"cell_type": "markdown",
"id": "9f1a6f30",
"metadata": {},
"source": [
"You could also opt for fast_any_tap that takes advantage of binary search instead of linear search internally."
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "1fa08adb",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------node result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" u | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 2 | \n",
" 9999.994675 | \n",
"
\n",
" \n",
" | 1 | \n",
" 4 | \n",
" 401.932237 | \n",
"
\n",
" \n",
" | 2 | \n",
" 6 | \n",
" 346.203709 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id u\n",
"0 2 9999.994675\n",
"1 4 401.932237\n",
"2 6 346.203709"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"------tap regulator result------\n",
"\n",
"----------fast_any_tap----------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" energized | \n",
" tap_pos | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 8 | \n",
" 1 | \n",
" -1 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id energized tap_pos\n",
"0 8 1 -1"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# one-time power flow calculation with automatic tap changing\n",
"output_data6f = model5.calculate_power_flow(tap_changing_strategy=TapChangingStrategy.fast_any_tap)\n",
"\n",
"# the node at the control side of the transformer now has a voltage within the specified voltage band\n",
"print(\"------node result------\")\n",
"display(pd.DataFrame(output_data6f[ComponentType.node])[[AttributeType.id, AttributeType.u]])\n",
"\n",
"print(\"\\n------tap regulator result------\")\n",
"print(\"\\n----------fast_any_tap----------\")\n",
"display(pd.DataFrame(output_data6f[ComponentType.transformer_tap_regulator]))"
]
},
{
"cell_type": "markdown",
"id": "7828a4e3",
"metadata": {},
"source": [
"**NOTE:** the tap positions obtained using the `any_valid_tap` and `fast_any_tap` strategy may depend on the initial tap position of the transformers."
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "be276930",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------transformer batch update------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" from_status | \n",
" to_status | \n",
" tap_pos | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 3 | \n",
" -128 | \n",
" -128 | \n",
" 0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 3 | \n",
" -128 | \n",
" -128 | \n",
" 1 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id from_status to_status tap_pos\n",
"0 3 -128 -128 0\n",
"1 3 -128 -128 1"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"------node_4 batch result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" u | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 4 | \n",
" 397.867176 | \n",
"
\n",
" \n",
" | 1 | \n",
" 4 | \n",
" 393.881868 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id u\n",
"0 4 397.867176\n",
"1 4 393.881868"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"------tap regulator batch result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" energized | \n",
" tap_pos | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 8 | \n",
" 1 | \n",
" 0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 8 | \n",
" 1 | \n",
" 1 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id energized tap_pos\n",
"0 8 1 0\n",
"1 8 1 1"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"transformer_update = initialize_array(DatasetType.update, ComponentType.transformer, (2, 1))\n",
"transformer_update[AttributeType.id] = 3\n",
"transformer_update[AttributeType.tap_pos] = [[0], [1]]\n",
"\n",
"update_data = {ComponentType.transformer: transformer_update}\n",
"\n",
"print(\"------transformer batch update------\")\n",
"display(pd.DataFrame(update_data[ComponentType.transformer][:, 0]))\n",
"\n",
"# power flow batch calculation with automatic tap changing\n",
"output_data = model5.calculate_power_flow(\n",
" update_data=update_data, tap_changing_strategy=TapChangingStrategy.fast_any_tap\n",
")\n",
"\n",
"print(\"------node_4 batch result------\")\n",
"display(pd.DataFrame(output_data[ComponentType.node][:, 1])[[AttributeType.id, AttributeType.u]]) # only output node 1\n",
"\n",
"print(\"\\n------tap regulator batch result------\")\n",
"display(pd.DataFrame(output_data[ComponentType.transformer_tap_regulator][:, 0]))"
]
},
{
"cell_type": "markdown",
"id": "6f6cd15c",
"metadata": {},
"source": [
"### Maximum voltage tap position strategy\n",
"\n",
"To specifically optimize for the higher end of the voltage band, the `max_voltage_tap` tap changing strategy can be provided."
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "21b01a77",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------node result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" u | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 2 | \n",
" 9999.994683 | \n",
"
\n",
" \n",
" | 1 | \n",
" 4 | \n",
" 406.079525 | \n",
"
\n",
" \n",
" | 2 | \n",
" 6 | \n",
" 352.021534 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id u\n",
"0 2 9999.994683\n",
"1 4 406.079525\n",
"2 6 352.021534"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"------tap regulator result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" energized | \n",
" tap_pos | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 8 | \n",
" 1 | \n",
" -2 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id energized tap_pos\n",
"0 8 1 -2"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# one-time power flow calculation with automatic tap changing\n",
"output_data5 = model5.calculate_power_flow(tap_changing_strategy=TapChangingStrategy.max_voltage_tap)\n",
"\n",
"print(\"------node result------\")\n",
"display(pd.DataFrame(output_data5[ComponentType.node])[[AttributeType.id, AttributeType.u]])\n",
"\n",
"print(\"\\n------tap regulator result------\")\n",
"display(pd.DataFrame(output_data5[ComponentType.transformer_tap_regulator]))"
]
},
{
"cell_type": "markdown",
"id": "7b8ab2a2",
"metadata": {},
"source": [
"### Minimum voltage tap position strategy\n",
"\n",
"To specifically optimize for the lower end of the voltage band, the `min_voltage_tap` tap changing strategy can be provided."
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "c0314199",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------node result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" u | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 2 | \n",
" 9999.994657 | \n",
"
\n",
" \n",
" | 1 | \n",
" 4 | \n",
" 393.881868 | \n",
"
\n",
" \n",
" | 2 | \n",
" 6 | \n",
" 334.529465 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id u\n",
"0 2 9999.994657\n",
"1 4 393.881868\n",
"2 6 334.529465"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"------tap regulator result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" energized | \n",
" tap_pos | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 8 | \n",
" 1 | \n",
" 1 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id energized tap_pos\n",
"0 8 1 1"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# one-time power flow calculation with automatic tap changing\n",
"output_data5 = model5.calculate_power_flow(tap_changing_strategy=TapChangingStrategy.min_voltage_tap)\n",
"\n",
"print(\"------node result------\")\n",
"display(pd.DataFrame(output_data5[ComponentType.node])[[AttributeType.id, AttributeType.u]])\n",
"\n",
"print(\"\\n------tap regulator result------\")\n",
"display(pd.DataFrame(output_data5[ComponentType.transformer_tap_regulator]))"
]
},
{
"cell_type": "markdown",
"id": "01a473bd",
"metadata": {},
"source": [
"### Automatic tap changing with line drop compensation\n",
"\n",
"In the above examples, the voltage at the low-voltage side of the transformer is controlled. However, the load is still connected to a node with a voltage lower than 390 V.\n",
"\n",
"To regulate the node that the load is connected to, the voltage needs to be compensated for the voltage drop over the line.\n",
"\n",
"```txt\n",
" (tap_side) (control side)\n",
"source_1 --- node_2 --- transformer_3 --- node_4 --- line_5 --- node_6 --- load_7\n",
" | | :\n",
" regulator_8 <-----/ <......................./ (line drop compensation)\n",
" (control voltage) \n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "ac091392",
"metadata": {},
"outputs": [],
"source": [
"# use the same input data\n",
"input_data6 = {component: component_data.copy() for component, component_data in input_data5.items()}\n",
"\n",
"# set the regulator's line drop compensation\n",
"input_data6[ComponentType.transformer_tap_regulator][AttributeType.line_drop_compensation_r] = [10.0]\n",
"\n",
"# construction\n",
"model6 = PowerGridModel(input_data=input_data6)"
]
},
{
"cell_type": "markdown",
"id": "bb89ad98",
"metadata": {},
"source": [
"The result of the power flow calculation with automatic tap changing contains a voltage at the node that the load is connected to that is within the specified voltage band."
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "9b66d16e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------node result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" u | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 2 | \n",
" 9999.994731 | \n",
"
\n",
" \n",
" | 1 | \n",
" 4 | \n",
" 437.642686 | \n",
"
\n",
" \n",
" | 2 | \n",
" 6 | \n",
" 393.354002 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id u\n",
"0 2 9999.994731\n",
"1 4 437.642686\n",
"2 6 393.354002"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"------tap regulator result------\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" energized | \n",
" tap_pos | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 8 | \n",
" 1 | \n",
" -9 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id energized tap_pos\n",
"0 8 1 -9"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# one-time power flow calculation with automatic tap changing\n",
"output_data6 = model6.calculate_power_flow(tap_changing_strategy=TapChangingStrategy.any_valid_tap)\n",
"\n",
"print(\"------node result------\")\n",
"display(pd.DataFrame(output_data6[ComponentType.node])[[AttributeType.id, AttributeType.u]])\n",
"\n",
"print(\"\\n------tap regulator result------\")\n",
"display(pd.DataFrame(output_data6[ComponentType.transformer_tap_regulator]))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "power-grid-model",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}